package cn.texous.starter.sms.handler;

import cn.texous.starter.sms.config.properties.AliyunSmsProperties;
import cn.texous.starter.sms.config.properties.SmsProperties;
import cn.texous.starter.sms.model.SendInfo;
import cn.texous.starter.sms.model.SendResult;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2019/8/23 10:55
 */
@Slf4j
public class AliyunSmsHandler implements SmsHandler {
    private static final String CHANNEL = "aliyun-sms";

    private SmsProperties smsProperties;
    private AliyunSmsProperties aliyunSmsProperties;
    private IAcsClient acsClient;

    public AliyunSmsHandler(IAcsClient acsClient, SmsProperties smsProperties) {
        this.acsClient = acsClient;
        this.smsProperties = smsProperties;
        this.aliyunSmsProperties = smsProperties.getAliyun();
    }

    @Override
    public SendResult send(SendInfo sendInfo) {
        SendResult sendResult = new SendResult(CHANNEL);
        try {
            //组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();
            //必填:待发送手机号
            request.setPhoneNumbers(sendInfo.getMobile());
            request.setSignName(aliyunSmsProperties.getSignName());
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(smsProperties
                    .getTemplate().getAliyun().get(sendInfo.getTemplate()));

            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            request.setTemplateParam(getParamStr(parserToMap(sendInfo.getParams(), false)));
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
            log.info(new Gson().toJson(sendSmsResponse));
            if (sendSmsResponse.getCode() != null
                    && sendSmsResponse.getCode().equals("OK")) {
                log.info("阿里云 短信发送成功！");
                sendResult.setCode(SendResult.SUCCESS);
                return sendResult;
            }
            log.error("阿里云 短信发送失败：{}", new Gson().toJson(sendInfo));
            generatorErrorMessage(sendResult, sendSmsResponse);
        } catch (Exception e) {
            log.error(String.format("阿里云 短信发送失败：%s", e.getMessage()), e);
            sendResult.setErrorCode("0");
            sendResult.setErrorMsg("短信验证码发送失败！");
        }
        return sendResult;
    }

    @Override
    public String channel() {
        return CHANNEL;
    }

    @Override
    public boolean init() {
        return aliyunSmsProperties.getInit();
    }

    @Override
    public int order() {
        return aliyunSmsProperties.getOrder();
    }

    private static void generatorErrorMessage(SendResult result, SendSmsResponse response) {
        String code = response.getCode();
        String message = errorCodeMap.get(code);
        result.setErrorCode(code);
        result.setErrorMsg(message);
    }

    private static Map<String, String> errorCodeMap = new HashMap<>();

    static {
        errorCodeMap.put("isv.SMS_SIGNATURE_SCENE_ILLEGAL", "签名的适用场景与短信类型不匹配");
        errorCodeMap.put("isv.EXTEND_CODE_ERROR", "发送短信时不同签名的短信使用了相同扩展码。");
        errorCodeMap.put("isv.DOMESTIC_NUMBER_NOT_SUPPORTED", "国际/港澳台消息模板仅支持发送国际、港澳台地区的号码。");
        errorCodeMap.put("isv.DAY_LIMIT_CONTROL", "已经达到您在控制台设置的短信日发送量限额值。");
        errorCodeMap.put("isv.SMS_CONTENT_ILLEGAL", "短信内容包含禁止发送内容。");
        errorCodeMap.put("isv.SMS_SIGN_ILLEGAL", "签名禁止使用。");
        errorCodeMap.put("isp.RAM_PERMISSION_DENY", "RAM权限不足。");
        errorCodeMap.put("isv.OUT_OF_SERVICE", "余额不足。余额不足时，套餐包中即使有短信额度也无法发送短信。");
        errorCodeMap.put("isv.PRODUCT_UN_SUBSCRIPT", "该AK所属的账号尚未开通云通信的服务，包括短信、语音、流量等服务。");
        errorCodeMap.put("isv.PRODUCT_UNSUBSCRIBE",
                "该AK所属的账号尚未开通当前接口的产品，例如仅开通了短信服务的用户调用语音接口时会产生此报错信息。");
        errorCodeMap.put("isv.ACCOUNT_NOT_EXISTS", "使用了错误的账户名称或AK。");
        errorCodeMap.put("isv.ACCOUNT_ABNORMAL", "账户异常。");
        errorCodeMap.put("isv.SMS_TEMPLATE_ILLEGAL", "短信模板不存在，或未经审核通过。");
        errorCodeMap.put("isv.SMS_SIGNATURE_ILLEGAL", "签名不存在，或未经审核通过。");
        errorCodeMap.put("isv.INVALID_PARAMETERS", "参数格式不正确。");
        errorCodeMap.put("isp.SYSTEM_ERROR", "系统错误。");
        errorCodeMap.put("isv.MOBILE_NUMBER_ILLEGAL", "手机号码格式错误。");
        errorCodeMap.put("isv.MOBILE_COUNT_OVER_LIMIT", "参数PhoneNumbers中指定的手机号码数量超出限制。");
        errorCodeMap.put("isv.TEMPLATE_MISSING_PARAMETERS", "参数TemplateParam中，变量未全部赋值。");
        errorCodeMap.put("isv.BUSINESS_LIMIT_CONTROL", "短信发送频率超限。");
        errorCodeMap.put("isv.INVALID_JSON_PARAM", "参数格式错误，不是合法的JSON格式。");
        errorCodeMap.put("isv.BLACK_KEY_CONTROL_LIMIT", "黑名单管控是指变量内容含有限制发送的内容，例如变量中不允许透传URL。");
        errorCodeMap.put("isv.PARAM_LENGTH_LIMIT", "参数超出长度限制。");
        errorCodeMap.put("isv.PARAM_NOT_SUPPORT_URL", "黑名单管控是指变量内容含有限制发送的内容，例如变量中不允许透传URL。");
        errorCodeMap.put("isv.AMOUNT_NOT_ENOUGH", "当前账户余额不足。");
        errorCodeMap.put("isv.TEMPLATE_PARAMS_ILLEGAL", "变量内容含有限制发送的内容，例如变量中不允许透传URL。");
        errorCodeMap.put("SignatureDoesNotMatch", "签名（Signature）加密错误。");
        errorCodeMap.put("InvalidTimeStamp.Expired", "一般由于时区差异造成时间戳错误，发出请求的时间和服务器接收到请求的时间不在15分钟内。");
        errorCodeMap.put("SignatureNonceUsed", "唯一随机数重复，SignatureNonce为唯一随机数，用于防止网络重放攻击。");
        errorCodeMap.put("InvalidVersion", "版本号（Version）错误。");
        errorCodeMap.put("InvalidAction.NotFound", "参数Action中指定的接口名错误。");
    }
}
